package demo.mianshi.thread;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class _生产消费2 {
    public static void main(String[] args) {
        /**
         *  蜜蜂是生产者，熊是消费者。蜜蜂生产蜂蜜是累加的过程，
         *   熊吃蜂蜜是批量（满100吃掉）的过程。
         *   生产者和消费者之间使用通知方式告知对方。注意不能出现死锁的现象。
         *   100只蜜蜂，每次生产的蜂蜜是1.
         *   熊吃蜂蜜是20（批量的情况）。
         */
        HoneyProduct production = new HoneyProduct();
        new Bear(production).start();
        for (int i = 0; i < 100; i++) {
            new Bee(production, i).start();
        }
    }

    static class HoneyProduct {
        private int bee = 100;
        private int bear_count = 20;
        private int honey = 0;
        private int honey_max = 100;
        private Lock lock = new ReentrantLock();
        private Condition full = lock.newCondition();
        private Condition notFull = lock.newCondition();

        public void product(int i) {
            lock.lock();
            try {
                // 满通知熊
                while (honey >= honey_max) {
                    notFull.await();
                }
                honey++;
                System.out.println("蜜蜂" + i + "生产1,当前蜂蜜:" + honey);
                if (honey == honey_max) {
                    System.out.println("蜂蜜满，通知熊");
                    full.signal();
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }

        public void eat() {
            lock.lock();
            try {
                // 蜂蜜未满 不能吃
                while (honey <= 0) {
                    System.out.println("吃光了");
                    full.await();
                }
                int eat = Math.min(honey, bear_count);
                honey -= eat;
                System.out.println("熊吃了" + eat + ",还剩" + honey);
                notFull.signalAll();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            } finally {
                lock.unlock();
            }
        }
    }

    static class Bee extends Thread {
        private final HoneyProduct product;
        private final int i;

        Bee(HoneyProduct product, int i) {
            this.product = product;
            this.i = i;
        }

        @Override
        public void run() {
            while (true) {
                product.product(i);
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    static class Bear extends Thread {
        private final HoneyProduct product;

        Bear(HoneyProduct product) {
            this.product = product;
        }

        @Override
        public void run() {
            while (true) {
                product.eat();
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
